home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-13 / tde3.zip / MACRO.C < prev    next >
C/C++ Source or Header  |  1993-06-05  |  26KB  |  739 lines

  1. /*
  2.  * The "macro" routines in TDE are not really macro routines in the classical
  3.  * sense.  In TDE, "macros" are just recordings of key sequences.  But,
  4.  * actually, I find the ability to record and playback keystrokes generally
  5.  * more useful than writing a macro.  Being that I'm so stupid, it takes me
  6.  * half the morning to write and half the afternoon to debug a simple classical
  7.  * macro.  For most of my routine, little jobs, I find it more convenient
  8.  * to record my keystrokes and playback those keystrokes at appropriate places
  9.  * in a file.  It just seems easier for me to "teach" the editor what to do
  10.  * rather than "instruct" the editor what to do.
  11.  *
  12.  * New editor name:  TDE, the Thomson-Davis Editor.
  13.  * Author:           Frank Davis
  14.  * Date:             June 5, 1991, version 1.0
  15.  * Date:             July 29, 1991, version 1.1
  16.  * Date:             October 5, 1991, version 1.2
  17.  * Date:             January 20, 1992, version 1.3
  18.  * Date:             February 17, 1992, version 1.4
  19.  * Date:             April 1, 1992, version 1.5
  20.  * Date:             June 5, 1992, version 2.0
  21.  * Date:             October 31, 1992, version 2.1
  22.  * Date:             April 1, 1993, version 2.2
  23.  * Date:             June 5, 1993, version 3.0
  24.  *
  25.  * This modification of Douglas Thomson's code is released into the
  26.  * public domain, Frank Davis.  You may distribute it freely.
  27.  */
  28.  
  29.  
  30. #include "tdestr.h"             /* tde types */
  31. #include "common.h"
  32. #include "define.h"
  33. #include "tdefunc.h"
  34.  
  35.  
  36. /*
  37.  *              keystroke record functions
  38.  */
  39.  
  40. /*
  41.  * Name:    record_on_off
  42.  * Purpose: save keystrokes in keystroke buffer
  43.  * Date:    April 1, 1992
  44.  * Passed:  window:  pointer to current window
  45.  * Notes:   -1 in .next field indicates the end of a recording
  46.  *          -1 in .key field indicates the initial, unassigned macro key
  47.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  48.  */
  49. int  record_on_off( WINDOW *window )
  50. {
  51. register int next;
  52. int  prev;
  53. int  line;
  54. int  key;
  55. int  func;
  56. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  57.  
  58.    mode.record = !mode.record;
  59.    if (mode.record == TRUE) {
  60.       line = window->bottom_line;
  61.       show_avail_strokes( );
  62.       save_screen_line( 0, line, line_buff );
  63.       /*
  64.        * press key that will play back recording
  65.        */
  66.       set_prompt( main11, line );
  67.  
  68.       /*
  69.        * get the candidate macro key and look up the function assigned to it.
  70.        */
  71.       key = getkey( );
  72.       func = getfunc( key );
  73.  
  74.       /*
  75.        * the key must be an unused, recognized function key or a function
  76.        *  key assigned to a previously defined macro.  we also need room
  77.        *  in the macro structure.
  78.        */
  79.       if (key <= 256 || (func != 0 && func != PlayBack)) {
  80.          /*
  81.           * cannot assign a recording to this key
  82.           */
  83.          error( WARNING, line, main12 );
  84.          mode.record = FALSE;
  85.       } else if (g_status.stroke_count == 0) {
  86.          /*
  87.           * no more room in recording buffer
  88.           */
  89.          error( WARNING, line, main13 );
  90.          mode.record = FALSE;
  91.       } else {
  92.  
  93.          /*
  94.           * everything is everything so far, just check for a prev macro
  95.           */
  96.          prev = OK;
  97.          if (func == PlayBack) {
  98.             /*
  99.              * overwrite recording (y/n)?
  100.              */
  101.             set_prompt( main14, line );
  102.             if (get_yn( ) == A_NO) {
  103.                prev = ERROR;
  104.                mode.record = FALSE;
  105.             }
  106.          }
  107.          if (prev == OK) {
  108.             g_status.recording_key = key;
  109.             next = macro.first_stroke[key-256];
  110.  
  111.             /*
  112.              * if key has already been assigned to a macro, clear macro def.
  113.              */
  114.             if (next != STROKE_LIMIT+1) {
  115.                do {
  116.                   prev = next;
  117.                   next = macro.strokes[next].next;
  118.                   macro.strokes[prev].key  = MAX_KEYS+1;
  119.                   macro.strokes[prev].next = STROKE_LIMIT+1;
  120.                   ++g_status.stroke_count;
  121.                } while (next != -1);
  122.                show_avail_strokes( );
  123.             }
  124.  
  125.             /*
  126.              * find the first open space and initialize
  127.              */
  128.             for (next=0; macro.strokes[next].next != STROKE_LIMIT+1;)
  129.                next++;
  130.             macro.first_stroke[key-256] = next;
  131.             macro.strokes[next].key  = -1;
  132.             macro.strokes[next].next = -1;
  133.             key_func.key[key-256] = PlayBack;
  134.             /*
  135.              * recording
  136.              */
  137.             s_output( main15, g_display.mode_line, 22,
  138.                       g_display.mode_color | 0x80 );
  139.          }
  140.       }
  141.       restore_screen_line( 0, line, line_buff );
  142.    }
  143.  
  144.    /*
  145.     * the flashing "Recording" and the stroke count write over the modes.
  146.     *  when we get thru defining a macro, redisplay the modes.
  147.     */
  148.    if (mode.record == FALSE) {
  149.       memset( line_buff, ' ', 36 );
  150.       line_buff[36] = '\0';
  151.       s_output( line_buff, g_display.mode_line, 22, g_display.mode_color );
  152.       show_tab_modes( );
  153.       show_indent_mode( );
  154.       show_sync_mode( );
  155.       show_search_case( );
  156.       show_wordwrap_mode( );
  157.  
  158.       /*
  159.        * let's look at the macro.  if the first .key of the macro is
  160.        *  still -1, which is the initial unassigned key in a macro, reset
  161.        *  the macro so other keys may be assigned to this node.
  162.        */
  163.       key = g_status.recording_key;
  164.       if (key != 0) {
  165.          next = macro.first_stroke[key-256];
  166.          if (macro.strokes[next].key == -1) {
  167.             macro.strokes[next].key  = MAX_KEYS+1;
  168.             macro.strokes[next].next = STROKE_LIMIT+1;
  169.             macro.first_stroke[key-256] = STROKE_LIMIT+1;
  170.             if (getfunc( key ) == PlayBack)
  171.                key_func.key[key-256] = 0;
  172.          }
  173.       }
  174.       g_status.recording_key = 0;
  175.    }
  176.    return( OK );
  177. }
  178.  
  179.  
  180. /*
  181.  * Name:    record_keys
  182.  * Purpose: save keystrokes in keystroke buffer
  183.  * Date:    April 1, 1992
  184.  * Passed:  line: line to display prompts
  185.  * Notes:   -1 in .next field indicates the end of a recording
  186.  *          STROKE_LIMIT+1 in .next field indicates an unused space.
  187.  */
  188. void record_keys( int line )
  189. {
  190. register int next;
  191. register int prev;
  192. int  key;
  193. int  func;
  194.  
  195.    if (mode.record == TRUE) {
  196.       if (g_status.stroke_count == 0)
  197.          /*
  198.           * no more room in recording buffer
  199.           */
  200.          error( WARNING, line, main13 );
  201.       else {
  202.          key = g_status.key_pressed;
  203.          func = getfunc( key );
  204.          if (func != RecordMacro && func != SaveMacro && func != LoadMacro &&
  205.              func != ClearAllMacros) {
  206.  
  207.             /*
  208.              * a -1 in the next field marks the end of the keystroke recording.
  209.              */
  210.             next = macro.first_stroke[g_status.recording_key - 256];
  211.             if (macro.strokes[next].next != STROKE_LIMIT+1) {
  212.                while (macro.strokes[next].next != -1)
  213.                   next = macro.strokes[next].next;
  214.             }
  215.             prev = next;
  216.  
  217.             /*
  218.              * now find an open space to record the current key.
  219.              */
  220.             if (macro.strokes[next].key != -1) {
  221.                for (; next < STROKE_LIMIT &&
  222.                             macro.strokes[next].next != STROKE_LIMIT+1;)
  223.                   next++;
  224.                if (next == STROKE_LIMIT) {
  225.                   for (next=0; next < prev &&
  226.                                macro.strokes[next].next != STROKE_LIMIT+1;)
  227.                      next++;
  228.                }
  229.             }
  230.             if (next == prev && macro.strokes[prev].key != -1)
  231.                /*
  232.                 * no more room in recording buffer
  233.                 */
  234.                error( WARNING, line, main13 );
  235.             else {
  236.             /*
  237.              * next == prev if we are recording the initial macro node.
  238.              */
  239.                macro.strokes[prev].next = next;
  240.                macro.strokes[next].next = -1;
  241.                macro.strokes[next].key  = key;
  242.                g_status.stroke_count--;
  243.                show_avail_strokes( );
  244.             }
  245.          }
  246.       }
  247.    }
  248. }
  249.  
  250.  
  251. /*
  252.  * Name:    show_avail_strokes
  253.  * Purpose: show available free key strokes in lite bar at bottom of screen
  254.  * Date:    April 1, 1992
  255.  */
  256. void show_avail_strokes( void )
  257. {
  258. char strokes[MAX_COLS];
  259.  
  260.    s_output( main18, g_display.mode_line, 33, g_display.mode_color );
  261.    itoa( g_status.stroke_count, strokes, 10 );
  262.    s_output( "      ", g_display.mode_line, 51, g_display.mode_color );
  263.    s_output( strokes, g_display.mode_line, 51, g_display.mode_color );
  264. }
  265.  
  266.  
  267. /*
  268.  * Name:    save_strokes
  269.  * Purpose: save strokes to a file
  270.  * Date:    April 1, 1992
  271.  * Passed:  window:  pointer to current window
  272.  */
  273. int  save_strokes( WINDOW *window )
  274. {
  275. FILE *fp;                       /* file to be written */
  276. char name[MAX_COLS+2];          /* file name */
  277. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  278. register int rc;
  279. int  prompt_line;
  280. int  fattr;
  281.  
  282.    name[0] = '\0';
  283.    prompt_line = window->bottom_line;
  284.    save_screen_line( 0, prompt_line, line_buff );
  285.    /*
  286.     * name for macro file
  287.     */
  288.    if ((rc = get_name( main19, prompt_line, name,
  289.                  g_display.message_color )) == OK  &&  *name != '\0') {
  290.  
  291.       /*
  292.        * make sure it is OK to overwrite any existing file
  293.        */
  294.       rc = get_fattr( name, &fattr );
  295.       if (rc == OK) {
  296.          /*
  297.           * overwrite existing file
  298.           */
  299.          set_prompt( main20, prompt_line );
  300.          if (get_yn( ) != A_YES  ||  change_mode( name, prompt_line ) == ERROR)
  301.             rc = ERROR;
  302.       }
  303.       if (rc != ERROR) {
  304.          if ((fp = fopen( name, "wb" )) != NULL) {
  305.             fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  306.             fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  307.             fclose( fp );
  308.          }
  309.       }
  310.    }
  311.    restore_screen_line( 0, prompt_line, line_buff );
  312.    return( OK );
  313. }
  314.  
  315.  
  316. /*
  317.  * Name:    load_strokes
  318.  * Purpose: load strokes from a file
  319.  * Date:    April 1, 1992
  320.  * Passed:  window:  pointer to current window
  321.  * Notes:   show the user a file pick list.  I can never remember macro
  322.  *           file names or the directory in which they hide.  might as well
  323.  *           give the user a file pick list.
  324.  */
  325. int  load_strokes( WINDOW *window )
  326. {
  327. register FILE *fp;      /* file to be read */
  328. char dname[MAX_COLS];   /* directory search pattern */
  329. char stem[MAX_COLS];    /* directory stem */
  330. register int rc;
  331.  
  332.    dname[0] = '\0';
  333.    /*
  334.     * search path for macro file
  335.     */
  336.    if (get_name( main21, window->bottom_line, dname,
  337.                  g_display.message_color ) == OK  &&  *dname != '\0') {
  338.       if (validate_path( dname, stem ) == OK) {
  339.          rc = list_and_pick( dname, stem, window );
  340.  
  341.          /*
  342.           * if everything is everything, load in the file selected by user.
  343.           */
  344.          if (rc == OK) {
  345.             if ((fp = fopen( dname, "rb" )) != NULL && ceh.flag != ERROR) {
  346.                fwrite( ¯o.first_stroke[0], sizeof(int), MAX_KEYS, fp );
  347.                fwrite( ¯o.strokes[0], sizeof(STROKES), STROKE_LIMIT, fp );
  348.                fclose( fp );
  349.             }
  350.             if (ceh.flag == OK)
  351.                connect_macros( );
  352.          }
  353.       } else
  354.          /*
  355.           * invalid path or file name
  356.           */
  357.          error( WARNING, window->bottom_line, main22 );
  358.    }
  359.    return( OK );
  360. }
  361.  
  362.  
  363. /*
  364.  * Name:    clear_macro
  365.  * Purpose: reset all macro buffers, pointers, functions.
  366.  * Date:    April 1, 1992
  367.  * Notes:   reset the available macro stroke count.  reset all fields in
  368.  *           macro structure.  clear any keys assigned to macros in the
  369.  *           function assignment array.
  370.  */
  371. int  clear_macros( WINDOW *arg_filler )
  372. {
  373. register int i;
  374.  
  375.    g_status.stroke_count = STROKE_LIMIT;
  376.    for (i=0; i<STROKE_LIMIT; i++) {
  377.       macro.strokes[i].next = STROKE_LIMIT+1;
  378.       macro.strokes[i].key  = MAX_KEYS+1;
  379.    }
  380.    for (i=0; i<MAX_KEYS; i++) {
  381.       macro.first_stroke[i] = STROKE_LIMIT+1;
  382.       if (key_func.key[i] == PlayBack)
  383.          key_func.key[i] = 0;
  384.    }
  385.    return( OK );
  386. }
  387.  
  388.  
  389. /*
  390.  * Name:    connect_macros
  391.  * Purpose: hook up all (if any) macros to the function key definition table
  392.  * Date:    April 1, 1992
  393.  * Notes:   we need to connect all macro definitions to the key definition
  394.  *           table in the startup routine or when we read in a new macro
  395.  *           definition file.  the predefined func assignments take
  396.  *           precedence over macro definitions.
  397.  */
  398. void connect_macros( void )
  399. {
  400. register int i;
  401.  
  402.    /*
  403.     * reset the key function assignment array.  initially, no keys may be
  404.     *  assigned to a macro.
  405.     */
  406.    for (i=0; i<MAX_KEYS; i++)
  407.       if (key_func.key[i] == PlayBack)
  408.          key_func.key[i] = 0;
  409.  
  410.    /*
  411.     * now, find out how many free keystrokes are in the macro structure.
  412.     */
  413.    g_status.stroke_count = 0;
  414.    for (i=0; i<STROKE_LIMIT; i++)
  415.       if (macro.strokes[i].next == STROKE_LIMIT+1)
  416.          ++g_status.stroke_count;
  417.  
  418.    /*
  419.     * go thru the first stroke list to see if any key has been assigned to
  420.     *  a macro and connect the macro def to the key.  predefined function
  421.     *  assignments take precedence over macros.
  422.     */
  423.    for (i=0; i<MAX_KEYS; i++) {
  424.       if (macro.first_stroke[i] != STROKE_LIMIT+1)
  425.          if (key_func.key[i] == 0)
  426.             key_func.key[i] = PlayBack;
  427.    }
  428. }
  429.  
  430.  
  431. /*
  432.  *              keystroke play back functions
  433.  */
  434.  
  435.  
  436. /*
  437.  * Name:    play_back
  438.  * Purpose: play back a series of keystrokes assigned to key
  439.  * Date:    April 1, 1992
  440.  * Notes:   go thru the macro key list playing back the recorded keystrokes.
  441.  *          to let macros call other macros, we have to 1) save the next
  442.  *           keystroke of the current macro in a stack, 2) execute the
  443.  *           the called macro, 3) pop the key that saved by the calling
  444.  *           macro, 4) continue executing the macro, beginning with the
  445.  *           key we just popped.
  446.  *          use a local stack to store keys.  currently, there is room
  447.  *           for 256 keys -- should be enough room for most purposes.
  448.  */
  449. int  play_back( WINDOW *window )
  450. {
  451. int  key;
  452. int  rc = OK;
  453. int  popped;            /* flag is set when macro is popped */
  454.  
  455.    /*
  456.     * if we are recording a macro, let's just return if we do a recursive
  457.     *  definition.  Otherwise, we end up executing our recursive macro
  458.     *  while we are defining it.
  459.     */
  460.    if (mode.record == TRUE && g_status.key_pressed == g_status.recording_key)
  461.       rc = ERROR;
  462.    else {
  463.  
  464.       /*
  465.        * set the global macro flags, so other routines will know
  466.        *  if a macro is executing.
  467.        * set the stack_pointer to "empty" or -1.  initialize the popped
  468.        *  flag to FALSE being that we haven't popped any thing off the stack,
  469.        *  yet.
  470.        */
  471.       g_status.macro_executing = TRUE;
  472.       g_status.mstack_pointer  = -1;
  473.       popped = FALSE;
  474.       rc = OK;
  475.       while (rc == OK) {
  476.  
  477.          /*
  478.           * the first time thru the loop, popped is FALSE.  some lint
  479.           *  utilities may complain about key being used but not defined.
  480.           */
  481.          if (popped == FALSE) {
  482.  
  483.             /*
  484.              * find the first keystroke in the macro.  when we pop the stack,
  485.              *  all this stuff is reset by the pop -- do not reset it again.
  486.              */
  487.             g_status.macro_next = macro.first_stroke[g_status.key_pressed-256];
  488.             g_status.current_macro = g_status.key_pressed;
  489.             key = macro.strokes[g_status.macro_next].key;
  490.          }
  491.          popped = FALSE;
  492.          if (key != MAX_KEYS+1  &&  key != -1) {
  493.             do {
  494.  
  495.                /*
  496.                 * set up all editor variables as if we were entering
  497.                 *  keys from the keyboard.
  498.                 */
  499.                window = g_status.current_window;
  500.                display_dirty_windows( window );
  501.                ceh.flag = OK;
  502.                g_status.key_pressed = macro.strokes[g_status.macro_next].key;
  503.                g_status.command = getfunc( g_status.key_pressed );
  504.                if (g_status.wrapped  ||  g_status.key_pending) {
  505.                   g_status.key_pending = FALSE;
  506.                   g_status.wrapped = FALSE;
  507.                   show_search_message( CLR_SEARCH, g_display.mode_color );
  508.                }
  509.  
  510.                /*
  511.                 * while there are no errors or Control-Breaks, let's keep on
  512.                 *  executing a macro.  g_status.control_break is a global
  513.                 *  editor flag that is set in our Control-Break interrupt
  514.                 *  handler routine.
  515.                 */
  516.                if (g_status.control_break == TRUE) {
  517.                   rc = ERROR;
  518.                   break;
  519.                }
  520.  
  521.                /*
  522.                 * we haven't called any editor function yet.  we need
  523.                 *  to look at the editor command that is to be executed.
  524.                 *  if the command is PlayBack, we need to break out of
  525.                 *  this inner do loop and start executing the macro
  526.                 *  from the beginning (the outer do loop).
  527.                 *
  528.                 * if we don't break out now from a recursive macro, we will
  529.                 *  recursively call PlayBack and we will likely overflow
  530.                 *  the main (as opposed to the macro_stack) stack.
  531.                 */
  532.                if (g_status.command == PlayBack) {
  533.  
  534.                   /*
  535.                    * recursive macros are handled differently from
  536.                    *  macros that call other macros.
  537.                    * recursive macros - break out of this inner loop
  538.                    *  and begin executing the macro from the beg of macro.
  539.                    * standard macros - save the next instruction of this
  540.                    *  macro on the stack and begin executing the called macro.
  541.                    */
  542.                   if (g_status.current_macro != g_status.key_pressed) {
  543.                      if (push_macro_stack(
  544.                                    macro.strokes[g_status.macro_next].next )
  545.                                    != OK) {
  546.                         error( WARNING, window->bottom_line, ed16 );
  547.                         rc = ERROR;
  548.                      }
  549.                      g_status.macro_next =
  550.                                 macro.first_stroke[g_status.key_pressed-256];
  551.                      g_status.current_macro = g_status.key_pressed;
  552.                      key = macro.strokes[g_status.macro_next].key;
  553.  
  554.                      /*
  555.                       * execute called macro at beginning of this do loop.
  556.                       */
  557.                      continue;
  558.                   } else
  559.  
  560.                      /*
  561.                       * recursive macro - break out of this inner loop
  562.                       *  or else we may overflow the stack(s).
  563.                       */
  564.                      break;
  565.                }
  566.  
  567.  
  568.                /*
  569.                 * just as we assert before the main editor routine, let's
  570.                 *  assert in the macro function to make sure everything
  571.                 *  is everything.
  572.                 */
  573. #if defined(  __MSC__ )
  574.                assert( window != NULL );
  575.                assert( window->file_info != NULL );
  576.                assert( window->file_info->line_list != NULL );
  577.                assert( window->file_info->line_list_end != NULL );
  578.                assert( window->file_info->line_list_end->len == EOF );
  579.                assert( window->visible == TRUE );
  580.                assert( window->rline >= 0 );
  581.                assert( window->rline <= window->file_info->length + 1 );
  582.                assert( window->rcol >= 0 );
  583.                assert( window->rcol < MAX_LINE_LENGTH );
  584.                assert( window->ccol >= window->start_col );
  585.                assert( window->ccol <= window->end_col );
  586.                assert( window->bcol >= 0 );
  587.                assert( window->bcol < MAX_LINE_LENGTH );
  588.                assert( window->bcol == window->rcol-(window->ccol - window->start_col) );
  589.                assert( window->start_col >= 0 );
  590.                assert( window->start_col < window->end_col );
  591.                assert( window->end_col < g_display.ncols );
  592.                assert( window->cline >= window->top_line );
  593.                assert( window->cline <= window->bottom_line );
  594.                assert( window->top_line > 0 );
  595.                assert( window->top_line <= window->bottom_line );
  596.                assert( window->bottom_line < MAX_LINES );
  597.                assert( window->bin_offset >= 0 );
  598.                if (window->ll->next == NULL)
  599.                   assert( window->ll->len == EOF );
  600.                else
  601.                   assert( window->ll->len >= 0 );
  602.                assert( window->ll->len <  MAX_LINE_LENGTH );
  603. #endif
  604.  
  605.  
  606.                if (g_status.command >= 0 && g_status.command < NUM_FUNCS)
  607.                    rc = (*do_it[g_status.command])( window );
  608.                g_status.macro_next =
  609.                           macro.strokes[g_status.macro_next].next;
  610.             } while (rc == OK  &&  g_status.macro_next != -1);
  611.  
  612.             /*
  613.              * if we have come the end of a macro definition and there
  614.              *  are no keys saved on the stack, we have finished our
  615.              *  macro.  get out.
  616.              */
  617.             if (g_status.macro_next == -1 && g_status.mstack_pointer < 0)
  618.                rc = ERROR;
  619.             else if (rc != ERROR  &&  g_status.mstack_pointer >= 0) {
  620.  
  621.                /*
  622.                 * if this is a recursive macro, don't pop the stack
  623.                 *  because we didn't push.
  624.                 * for a standard macro, get back the next key in the
  625.                 *  calling macro.
  626.                 */
  627.                if (g_status.current_macro != g_status.key_pressed) {
  628.                   if (pop_macro_stack( &g_status.macro_next ) != OK) {
  629.                      error( WARNING, window->bottom_line, ed17 );
  630.                      rc = ERROR;
  631.                   } else {
  632.                      popped = TRUE;
  633.                      key = macro.strokes[g_status.macro_next].key;
  634.                   }
  635.                }
  636.             }
  637.          }
  638.       }
  639.       g_status.macro_executing = FALSE;
  640.    }
  641.    return( OK );
  642. }
  643.  
  644.  
  645. /*
  646.  * Name:    push_macro_stack
  647.  * Purpose: push the next key in a currently executing macro on local stack
  648.  * Date:    October 31, 1992
  649.  * Notes:   finally got tired of letting macros only "jump" and not call
  650.  *           other macros.
  651.  *          the first time in, stack_pointer is -1.
  652.  */
  653. int  push_macro_stack( int key )
  654. {
  655.    /*
  656.     * first, make sure we have room to push the key.
  657.     */
  658.    if (g_status.mstack_pointer+1 < MAX_KEYS) {
  659.  
  660.       /*
  661.        * increment the stack pointer and store the pointer to the next key
  662.        *  of the currently executing macro.  store the currently executing
  663.        *  macro, too.
  664.        */
  665.       ++g_status.mstack_pointer;
  666.       macro_stack[g_status.mstack_pointer].key = key;
  667.       macro_stack[g_status.mstack_pointer].macro = g_status.current_macro;
  668.       return( OK );
  669.    } else
  670.       return( STACK_OVERFLOW );
  671. }
  672.  
  673.  
  674. /*
  675.  * Name:    pop_macro_stack
  676.  * Purpose: pop currently executing macro on local stack
  677.  * Date:    October 31, 1992
  678.  * Notes:   finally got tired of letting macros only "jump" and not "call"
  679.  *           other macros.
  680.  *          pop the macro stack.  stack pointer is pointing to last key saved
  681.  *           on stack.
  682.  */
  683. int  pop_macro_stack( int *key )
  684. {
  685.  
  686.    /*
  687.     * before we pop the stack, make sure there is something in the stack.
  688.     */
  689.    if (g_status.mstack_pointer >= 0) {
  690.  
  691.       /*
  692.        * pop the pointer to the next key and the current macro, then
  693.        *  decrement the stack_pointer.
  694.        */
  695.       *key = macro_stack[g_status.mstack_pointer].key;
  696.       g_status.current_macro = macro_stack[g_status.mstack_pointer].macro;
  697.       --g_status.mstack_pointer;
  698.       return( OK );
  699.    } else
  700.       return( STACK_UNDERFLOW );
  701. }
  702.  
  703.  
  704. /*
  705.  * Name:    Pause
  706.  * Purpose: Enter pause state for macros
  707.  * Date:    June 5, 1992
  708.  * Passed:  arg_filler:  argument to satify function prototype
  709.  * Returns: ERROR if the ESC key was pressed, OK otherwise.
  710.  * Notes:   this little function is quite useful in macro definitions.  if
  711.  *          it is called near the beginning of a macro, the user may decide
  712.  *          whether or not to stop the macro.
  713.  */
  714. int  pause( WINDOW *arg_filler )
  715. {
  716. int  c;
  717.  
  718.    /*
  719.     * tell user we are paused.  the '|  0x80' turns on the blink attribute
  720.     */
  721.    s_output( paused1, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  722.    s_output( paused2, g_display.mode_line, 23+strlen( paused1 ),
  723.              g_display.mode_color );
  724.  
  725.    /*
  726.     * get the user's response and restore the mode line.
  727.     */
  728.    c = getkey( );
  729.    show_modes( );
  730.    if (mode.record == TRUE) {
  731.       /*
  732.        * if recording a macro, show recording message
  733.        */
  734.       s_output( main15, g_display.mode_line, 23, g_display.mode_color | 0x80 );
  735.       show_avail_strokes( );
  736.    }
  737.    return( c == ESC ? ERROR : OK );
  738. }
  739.